using System.Text.Json;
using System.Text.Json.Serialization;
using Newtonsoft.Json.Linq;

namespace Vin.Extension.Framework.Converters.Json;

public class JTokenConverter : JsonConverter<JToken?>
{
    public override JToken? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.Null)
        {
            return null;
        }

        if (reader.TokenType == JsonTokenType.StartObject)
        {
            var json = JsonDocument.ParseValue(ref reader).RootElement.GetRawText();
            return JToken.Parse(json);
        }

        if (reader.TokenType == JsonTokenType.StartArray)
        {
            var json = JsonDocument.ParseValue(ref reader).RootElement.GetRawText();
            return JArray.Parse(json);
        }

        throw new JsonException($"Unexpected token type: {reader.TokenType}");
    }

    public override void Write(Utf8JsonWriter writer, JToken? value, JsonSerializerOptions options)
    {
        if (value == null)
        {
            writer.WriteNullValue();
            return;
        }

        switch (value.Type)
        {
            case JTokenType.Object:
            case JTokenType.Array:
                writer.WriteRawValue(value.ToString());
                break;
            case JTokenType.Integer:
                if(value.Type == JTokenType.Integer && value.Value<long>() > int.MaxValue)
                {
                    // Handle large integers as strings to avoid overflow
                    writer.WriteStringValue(value.ToString());
                }
                else
                {
                    // Write as number if within int range
                    writer.WriteNumberValue(value.Value<int>());
                }
                // writer.WriteNumberValue(value.Value<Int64>());
                break;
            case JTokenType.Float:
                writer.WriteNumberValue(value.Value<double>());
                break;
            case JTokenType.Boolean:
                writer.WriteBooleanValue(value.Value<bool>());
                break;
            case JTokenType.String:
                writer.WriteStringValue(value.ToString());
                break;
            default:
                writer.WriteStringValue(value.ToString());
                break;
        }
    }
}